import Utils from "../../../../../Utils";
import Facility from "../../../../facility/Facility";
import MainHome from "../../../../facility/priveteFacility/MainHome";
import Mine from "../../../../facility/pulbicFacility/Mine";
import { FacilityType, Gain } from "../../../../info/GameEnum";
import { Global } from "../../../../info/Global";
import { Location } from "../../../../info/Predefine";
import { AiEnvironment } from "../../AiGameAction";
import { DecisionNode } from "../../DecisionTree";

export default class DecisionCrystal extends DecisionNode {

    environment: AiEnvironment & { lackCrystal: number, lackOil: number, lackAll: number };

    constructor(environment: any) {
        super(environment);
        environment.minerCount = this.environment.player.allMiner.length;
        this.childDecisionNodes.push(new BuildMiningMachine(environment));
        this.childDecisionNodes.push(new RecruitingMiner(environment));
        this.childDecisionNodes.push(new UpgradeMiningQuantity(environment));
        this.childDecisionNodes.push(new UpgradeMiningSpeed(environment));
    }

    /**
     * 对晶矿的需求
     * @returns 
     */
    evaluate(): number {
        return this.environment.lackCrystal / this.environment.lackAll * 100;
    }
}

/**
 * 招募矿工
 */
class RecruitingMiner extends DecisionNode {

    /**
     * @returns 
     */
    evaluate(): number {
        if (!this.environment.gainFeasibility.get(Gain.招募矿工).every(i => i))
            return 0;

        let curCount = (<MainHome>this.environment.player.facilityArr[FacilityType.主基地][0]).minerArr.length;
        let limit = Global.FacilityInfo[FacilityType.主基地].每基地等级招募矿工上限[Math.min(this.environment.player.mainHomeLevel,  Global.FacilityInfo[FacilityType.主基地].每基地等级招募矿工上限.length - 1)];
        //基础得分10 
        let score = 10 + 90 - (curCount / limit * 90);
        return Math.ceil(score);
    }

    execute(): number {
        let mainHome = <MainHome>this.environment.player.facilityArr[FacilityType.主基地][0];
        mainHome.addMiner();
        return 0;
    }
}

/**
 * 建造矿机
 */
class BuildMiningMachine extends DecisionNode {

    environment: AiEnvironment;

    chooseLocation: Location[];
    canUsedLocation: Location[][];

    /**
     * 获取到所有可建造晶矿的地块
     * 打乱地块，给每个地块按周围晶矿数量打分，晶矿越多概率越大
     * 然后按各自概率随机获取到一个位置
     * 基础得分20, 矿数量得分60, 现有资源充裕程度得分20
     * 满分100
     * @returns 返回当前得分/理论上的最高得分 * 100
     */
    evaluate(): number {
        if (!this.environment.facilityFeasibility.get(FacilityType.矿机).every(i => i))
            return 0; // 条件未满足

        this.canUsedLocation = this.environment.player.getSpaceBySize(1);
        if (!this.canUsedLocation.length)
            return 0;//位置不够

        let price = this.environment.player.getPrice(FacilityType.矿机);
        let priceScore = 0 //来自建造所需的晶矿是否充裕的得分  最高分20

        //如果现有资源是需求资源的两倍
        if (this.environment.player.diamond / 2 >= price.diamond && this.environment.player.oil / 2 >= price.oil) {
            priceScore = 20;
        }

        return 100 + priceScore;
    }

    execute(): number {
        //避免数据太大，使用采样策略，超过二十个则随机采样20个
        let canUsedLocation = Utils.shuffleArray(this.canUsedLocation, 10);
        //按条件获取每个位置的得分
        //晶矿数量总分40分
        let condition = (facility: Facility) => facility.facilityType == FacilityType.晶矿;
        let locationScores = canUsedLocation.map((locations => {
            let score = 1,
                location = locations[0],
                crystalMines = this.environment.player.getFacilitiesByAraeAndView({ locationX: location.locationX - 5, locationY: location.locationY - 5 }, { locationX: location.locationX + 5, locationY: location.locationY + 5 }, condition),
                curCount: number = crystalMines.map((mine: Mine) => mine.curCount).reduce((acc, cur) => acc + cur, 0);
            if (curCount > 0) score += 5; //只要有，就得5分  
            score += Math.min((curCount / Global.MineMaxCount), 3) * 5  // 超过单个矿场总资源的3倍 则为满分，晶矿总量越高，得分越高，满分 5+15 =  20分
            return score;
        }));
        let totalLocationScore = locationScores.reduce((a, b) => a + b, 0);
        let randomIndex = Utils.getRandomIndexByProbability(locationScores, totalLocationScore);
        this.chooseLocation = canUsedLocation[randomIndex];
        this.environment.player.addFacility(FacilityType.矿机, this.chooseLocation);
        return 0;
    }
}

/**
 * 升级挖矿数量
 */
class UpgradeMiningQuantity extends DecisionNode {
    price: { diamond: number, oil: number };
    environment: AiEnvironment & { minerCount: number };

    /**
     * 基础得分 10分，来自矿工数量得分，40 来自资源充裕程度得分 20
     * 总分60分 
     * @returns 
     */
    evaluate(): number {
        if (!this.environment.gainFeasibility.get(Gain.采矿数量升级).every(b => b))
            return;

        this.price = Global.FacilityInfo[FacilityType.主基地].采矿数量.每等级升级要求[this.environment.player.miningCountLevel];

        let minerCount: number = this.environment.minerCount,//矿工总数量
            minerCountScore = Math.min(40, minerCount * this.environment.minerCount),
            priceDiamondScore = Math.min(10, this.environment.player.diamond / this.price.diamond * 5),
            priceOilScore = Math.min(10, this.environment.player.oil / this.price.oil * 5) // 有两倍就是5分 三倍以上10分
        return 10 + minerCountScore + priceDiamondScore + priceOilScore;
    }

    execute(): number {
        this.environment.player.miningCountLevelUp();
        return 0;
    }
}

/** 
 * 升级挖矿速度
 * 基础得分 10分，来自矿工数量得分40 来自资源充裕程度得分 20
 * 总分60分 
 */
class UpgradeMiningSpeed extends DecisionNode {
    price: { diamond: number, oil: number };
    environment: AiEnvironment & { minerCount: number };

    evaluate(): number {
        if (!this.environment.gainFeasibility.get(Gain.采矿速度升级).every(b => b))
            return;
        this.price = Global.FacilityInfo[FacilityType.主基地].矿工速度.每等级升级要求[this.environment.player.minerSpeedLevel];
        let minerCount: number = this.environment.minerCount,//矿工总数量
            minerCountScore = Math.min(40, minerCount * this.environment.minerCount),
            priceDiamondScore = Math.min(10, this.environment.player.diamond / this.price.diamond * 5),
            priceOilScore = Math.min(10, this.environment.player.oil / this.price.oil * 5) // 有两倍就是5分 三倍以上10分
        return 10 + minerCountScore + priceDiamondScore + priceOilScore;
    }

    execute(): number {
        this.environment.player.miningSpeedLevelUp();
        return 0;
    }
}

